package com.song.tools.trigger;

import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 触发器工具类
 *
 * @author song tools
 * @since 2024-07-19
 */
public class TriggerUtil {

    private static LockTemplate lockTemplate;

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final Lock LOCK = new ReentrantLock();

    /**
     * 触发器执行
     *
     * @param triggerContext 触发器上下文
     * @return 触发器响应
     */
    public static <TriggerRequest, TriggerResponse> TriggerResponse trigger(TriggerContext<TriggerRequest> triggerContext) {
        AbstractTriggerTemplate<TriggerRequest, TriggerResponse> trigger = TriggerFactory.getTrigger(triggerContext.getTriggerType());
        Objects.requireNonNull(trigger, () -> "未找到" + triggerContext.getTriggerType() + "触发器");
        return trigger.execute(triggerContext);
    }


    /**
     * 触发器执行，加锁限流<br>
     * <b>此处注意：上锁后不手动解锁，等待过期时间自动解锁</b>
     *
     * @param triggerContext 触发器上下文
     * @param expire         锁过期时间
     * @param acquireTimeout 获取锁超时时间
     * @return 触发器响应
     */
    public static <TriggerRequest, TriggerResponse> TriggerResponse triggerWithLock(TriggerContext<TriggerRequest> triggerContext, Long expire, Long acquireTimeout) {
        initLockTemplate();
        // 锁过期时间默认5秒
        expire = Optional.ofNullable(expire).orElse(5000L);
        // 获取锁超时时间默认0秒
        acquireTimeout = Optional.ofNullable(acquireTimeout).orElse(0L);

        // 计算锁key
        String key = serializeToJson(triggerContext);
        // 尝试获取锁
        LockInfo lockInfo = lockTemplate.lock(key, expire, acquireTimeout);

        // 获取锁失败
        if (lockInfo == null) {
            throw new RuntimeException("调用过于频繁，业务处理中，请稍后再试");
        }
        // 获取锁成功，触发器执行
        return trigger(triggerContext);
    }

    /**
     * 触发器执行，加锁限流<br>
     * <b>此处注意：上锁后不手动解锁，等待过期时间自动解锁</b>
     *
     * @param triggerContext 触发器上下文
     * @return 触发器响应
     */
    public static <TriggerRequest, TriggerResponse> TriggerResponse triggerWithLock(TriggerContext<TriggerRequest> triggerContext) {
        return triggerWithLock(triggerContext, null, null);
    }


    /**
     * 初始化lockTemplate
     */
    private static void initLockTemplate() {
        if (lockTemplate == null) {
            lockTemplate = SpringBeanUtil.getByClass(LockTemplate.class);
        }
        Objects.requireNonNull(lockTemplate, "lockTemplate is null");
    }


    /**
     * 序列化对象为json
     *
     * @param object 对象
     * @return json
     */
    private static String serializeToJson(Object object) {
        try {
            LOCK.lock();
            return OBJECT_MAPPER.writeValueAsString(object);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            LOCK.unlock();
        }
    }
}
